/*
* Copyright (c) 2024 Yarward Technology Development Co., LTD
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <stdbool.h>
#include "iotc_oh_wifi.h"
#include "iotc_oh_ble.h"
#include "iotc_oh_sdk.h"
#include "iotc_oh_device.h"
#include "securec.h"
#include "cJSON.h"
#include "iotc_conf.h"
#include "utils_assert.h"
#include "iotc_errcode.h"
#include "iotc_svc.h"
#include "iotc_svc_softap.h"
#include "utils_json.h"
#include "config_login_info.h"
#include "utils_common.h"
#include "securec.h"
#include "ohos_bt_gap.h"
#include "iotc_network.h"
#include "iotc_wifi.h"
#include "wifi_net_info.h"
#include "wifi_device.h"
#include "parameter.h"
#include "iotc_oh_demo_get.h"

#define JSON_STR_SNW "snw"

#define DEMO_LOG(...) do { \
        printf("DEMO[%s:%u]", __func__, __LINE__); \
        printf(__VA_ARGS__); \
        printf("\r\n"); \
    } while (0)

/**
 * [MUST] MODIFY ME
 * DEV_INFO为产品信息，应与云/APP侧配置一致
 */
static IotcDeviceInfo DEV_INFO = {
    .sn = "12345678",
    .prodId = "12345",
    .subProdId = "78",
    .model = "MODEL",
    .devTypeId = "1234",
    .devTypeName = "Dev Type Name",
    .manuId = "123",
    .manuName = "Manu Name",
    .devName = "IPC Camera",
    .fwv = "1.0.0",
    .hwv = "1.0.0",
    .swv = "1.0.0",
    .protType = IOTC_PROT_TYPE_BLE_AND_WIFI,
};
/**
 * [MUST] MODIFY ME
 * SVC_INFO为产品服务信息，应与云/APP侧配置一致
 */
static const IotcServiceInfo SVC_INFO[] = {
    {"switch", "switch"},
    {"snw", "snw"},
    {"restart", "restart"},
    {"gps", "gps"},
    {"devNetInfo", "devNetInfo"},
    {"allServices", "allServices"},
};

/**
 * [MUST] MODIFY ME
 * PIN_CODE为产品使用的配网PIN码，应与APP侧配置一致
 */
#if IOTC_CONF_AILIFE_SUPPORT
#else
static const char *PIN_CODE = "01234567";
#endif


/**
 * [MUST] MODIFY ME
 * AC_KEY为产品厂商的AC KEY，应与云侧配置一致
 */
const uint8_t AC_KEY[IOTC_AC_KEY_LEN] = {
    0x49, 0x3F, 0x45, 0x4A, 0x3A, 0x72, 0x38, 0x7B, 0x36, 0x32, 0x50, 0x3C, 0x49, 0x39, 0x62, 0x38,
    0x72, 0xCB, 0x6D, 0xC5, 0xAE, 0xE5, 0x4A, 0x82, 0xD3, 0xE5, 0x6D, 0xF5, 0x36, 0x82, 0x62, 0xEB,
    0x89, 0x30, 0x6C, 0x88, 0x32, 0x56, 0x23, 0xFD, 0xB8, 0x67, 0x90, 0xA7, 0x7B, 0x61, 0x1E, 0xAE
};


/**
 * [MUST] MODIFY ME
 * 下面代码为开关服务的实现样例
 * SwitchPutCharState函数为控制指令的处理，控制指令报文为{"on":1或0}
 * SwitchGetCharState函数为查询指令的处理
 * g_switch保存了开关的状态
 * 产品可以参考该DEMO并实现自己的服务函数添加到SVC_MAP中
 */
static bool g_switch = false;

static int32_t SwitchPutCharState(const IotcServiceInfo *svc, const char *data, uint32_t len)
{
    if (data == NULL || len == 0) {
        IOTC_LOGE("param invalid");
        return -1;
    }
    int32_t on = 0;
    cJSON *json = cJSON_Parse(data);
    if (json == NULL) {
        IOTC_LOGE("parse error");
        return -1;
    }

    if (!cJSON_IsArray(json)) {
        cJSON *st = cJSON_GetObjectItem(json, STR_JSON_SVC_TYPE);
        if (st == NULL || !cJSON_IsString(st)) {
            cJSON_Delete(json);
            IOTC_LOGE("get st error");
            return -1;
        }
        if (strcmp(cJSON_GetStringValue(st), svc->svcType)) {
            return 0;
        }
        cJSON *subdata = cJSON_GetObjectItem(json, STR_JSON_DATA);
        if (subdata == NULL) {
            cJSON_Delete(json);
            IOTC_LOGE("get data error");
            return -1;
        }
        cJSON *item = cJSON_GetObjectItem(json, "on");
        if (item == NULL || !cJSON_IsNumber(item)) {
            cJSON_Delete(json);
            IOTC_LOGE("get on error");
            return -1;
        }
        on = cJSON_GetNumberValue(item);
    } else {
        int size = cJSON_GetArraySize(json);
        for (int i = 0; i < size; i++) {
            cJSON *cur = cJSON_GetArrayItem(json, i);
            cJSON *st = cJSON_GetObjectItem(cur, STR_JSON_SVC_TYPE);
            if (st == NULL || !cJSON_IsString(st)) {
                cJSON_Delete(json);
                IOTC_LOGE("get st error");
                return -1;
            }
            if (strcmp(cJSON_GetStringValue(st), svc->svcType)) {
                return 0;
            }
            cJSON *subdata = cJSON_GetObjectItem(cur, STR_JSON_DATA);
            if (subdata == NULL) {
                cJSON_Delete(json);
                IOTC_LOGE("get data error");
                return -1;
            }
            cJSON *item = cJSON_GetObjectItem(subdata, "on");
            if (item == NULL || !cJSON_IsNumber(item)) {
                cJSON_Delete(json);
                IOTC_LOGE("get on error");
                return -1;
            }
            on = cJSON_GetNumberValue(item);
        }
    }

    DEMO_LOG("switch on put %d=>%d", g_switch, on);
    g_switch = on == 0 ? false : true;

    if (on == 0) {
        system("power-shell suspend");
    } else if (on == 1) {
        system("power-shell wakeup");
    }    
    cJSON_Delete(json);
    return 0;
}

static int32_t SwitchGetCharState(const IotcServiceInfo *svc, char **data, uint32_t *len)
{
    if (data == NULL || *data != NULL) {
        IOTC_LOGE("param invalid");
        return -1;
    }

    cJSON *json = cJSON_CreateObject();
    if (json == NULL) {
        IOTC_LOGE("create obj error");
        return -1;
    }
    
    int state = getScreenState();
    IOTC_LOGI("get screen state:%d",state);
    if (cJSON_AddNumberToObject(json, "on", state) == NULL) {
        cJSON_Delete(json);
        IOTC_LOGE("add num error");
        return -1;
    }
    *data = cJSON_PrintUnformatted(json);
    cJSON_Delete(json);
    if (*data == NULL) {
        IOTC_LOGE("json print error");
        return -1;
    }
    DEMO_LOG("switch on get %d", state);
    *len = strlen(*data);
    return 0;
}

static int32_t SnPutCharState(const IotcServiceInfo *svc, const char *data, uint32_t len)
{
    if (data == NULL || len == 0) {
        IOTC_LOGE("param invalid");
        return -1;
    }
    cJSON *json = cJSON_Parse(data);
    if (json == NULL) {
        IOTC_LOGE("parse error");
        return -1;
    }

    cJSON *item = cJSON_GetObjectItem(json, JSON_STR_SNW);
    if (item == NULL || !IotcJsonIsStr(item)) {
        cJSON_Delete(json);
        IOTC_LOGE("get on error");
        return -1;
    }
    IOTC_LOGI("sn on put =>%s", cJSON_GetStringValue(item));
    cJSON_Delete(json);
    return 0;
}

static int32_t SnGetCharState(const IotcServiceInfo *svc, char **data, uint32_t *len)
{
    if (data == NULL || *data != NULL) {
        IOTC_LOGE("param invalid");
        return -1;
    }

    cJSON *json = cJSON_CreateObject();
    if (json == NULL) {
        IOTC_LOGE("create obj error");
        return -1;
    }

    if (cJSON_AddStringToObject(json, JSON_STR_SNW, GetSerial()) == NULL) {
        cJSON_Delete(json);
        IOTC_LOGE("add num error");
        return -1;
    }

    *data = cJSON_PrintUnformatted(json);
    cJSON_Delete(json);
    if (*data == NULL) {
        IOTC_LOGE("json print error");
        return -1;
    }
    IOTC_LOGI("sn on get %s serial:%s", DEV_INFO.sn, GetSerial());
    *len = strlen(*data);
    return 0;
}

static bool g_restart = false;

static int32_t RestartPutCharState(const IotcServiceInfo *svc, const char *data, uint32_t len)
{
    if (data == NULL || len == 0) {
        IOTC_LOGE("param invalid");
        return -1;
    }
    int32_t restart = 0;
    cJSON *json = cJSON_Parse(data);
    if (json == NULL) {
        IOTC_LOGE("parse error");
        return -1;
    }
    
    if (!cJSON_IsArray(json)) {
        cJSON *st = cJSON_GetObjectItem(json, STR_JSON_SVC_TYPE);
        if (st == NULL || !cJSON_IsString(st)) {
            cJSON_Delete(json);
            IOTC_LOGE("get st error");
            return -1;
        }

        if (strcmp(cJSON_GetStringValue(st), svc->svcType)) {
            return 0;
        }
        cJSON *subdata = cJSON_GetObjectItem(json, STR_JSON_DATA);
        if (subdata == NULL) {
            cJSON_Delete(json);
            IOTC_LOGE("get data error");
            return -1;
        }

        cJSON *item = cJSON_GetObjectItem(json, "restart");
        if (item == NULL || !cJSON_IsNumber(item)) {
            cJSON_Delete(json);
            IOTC_LOGE("get restart error");
            return -1;
        }
        restart = cJSON_GetNumberValue(item);
    } else {
        int size = cJSON_GetArraySize(json);
        for (int i = 0; i < size; i++) {
            cJSON *cur = cJSON_GetArrayItem(json, i);
            cJSON *st = cJSON_GetObjectItem(cur, STR_JSON_SVC_TYPE);
            if (st == NULL || !cJSON_IsString(st)) {
                cJSON_Delete(json);
                IOTC_LOGE("get st error");
                return -1;
            }
            if (strcmp(cJSON_GetStringValue(st), svc->svcType)) {
                return 0;
            }
            cJSON *subdata = cJSON_GetObjectItem(cur, STR_JSON_DATA);
            if (subdata == NULL) {
                cJSON_Delete(json);
                IOTC_LOGE("get data error");
                return -1;
            }
            cJSON *item = cJSON_GetObjectItem(subdata, "restart");
            if (item == NULL || !cJSON_IsNumber(item)) {
                cJSON_Delete(json);
                IOTC_LOGE("get restart error");
                return -1;
            }
            restart = cJSON_GetNumberValue(item);
        }
    }

    DEMO_LOG("restart  put %d=>%d", g_restart, restart);
    g_restart = restart == 0 ? false : true;
    if (restart == 0) {
        g_restart = false;
        system("reboot");
    } else if (restart == 1) {
        g_restart = true;
        system("power-shell suspend");
    }
    cJSON_Delete(json);
    return 0;
}

static int32_t RestartGetCharState(const IotcServiceInfo *svc, char **data, uint32_t *len)
{
    if (data == NULL || *data != NULL) {
        IOTC_LOGE("param invalid");
        return -1;
    }

    cJSON *json = cJSON_CreateObject();
    if (json == NULL) {
        IOTC_LOGE("create obj error");
        return -1;
    }

    if (cJSON_AddNumberToObject(json, "restart", g_restart) == NULL) {
        cJSON_Delete(json);
        IOTC_LOGE("add num error");
        return -1;
    }
    *data = cJSON_PrintUnformatted(json);
    cJSON_Delete(json);
    if (*data == NULL) {
        IOTC_LOGE("json print error");
        return -1;
    }
    DEMO_LOG("restart get %d", g_restart);
    *len = strlen(*data);
    return 0;
}

static char g_latitude[20] = "30.496039";
static char g_longitude[20] = "114.546093";

static int32_t GpsPutCharState(const IotcServiceInfo *svc, const char *data, uint32_t len)
{
    if (data == NULL || len == 0) {
        IOTC_LOGE("param invalid");
        return -1;
    }
    cJSON *json = cJSON_Parse(data);
    if (json == NULL) {
        IOTC_LOGE("parse error");
        return -1;
    }
    
    if (!cJSON_IsArray(json)) {
        cJSON *st = cJSON_GetObjectItem(json, STR_JSON_SVC_TYPE);
        if (st == NULL || !cJSON_IsString(st)) {
            cJSON_Delete(json);
            IOTC_LOGE("get st error");
            return -1;
        }

        if (strcmp(cJSON_GetStringValue(st), svc->svcType)) {
            return 0;
        }
        cJSON *subdata = cJSON_GetObjectItem(json, STR_JSON_DATA);
        if (subdata == NULL) {
            cJSON_Delete(json);
            IOTC_LOGE("get data error");
            return -1;
        }
        if (cJSON_HasObjectItem(subdata, "latitude") == true) {
            cJSON *item = cJSON_GetObjectItem(subdata, "latitude");
            if (item == NULL || !cJSON_IsString(item)) {
                cJSON_Delete(json);
                IOTC_LOGE("get latitude error");
                return -1;
            }
            char latitude[20] = {0};
            strncpy(latitude, cJSON_GetStringValue(item), 19);
            latitude[19] = '\0';
            DEMO_LOG("latitude put %s=>%s", g_latitude, latitude);
            IOTC_LOGI("latitude put %s=>%s", g_latitude, latitude);
            if (strcmp(g_latitude, latitude)) {
                strncpy(g_latitude, latitude, 19);
                g_latitude[19] = '\0';
            }
        }

        if (cJSON_HasObjectItem(subdata, "longitude") == true) {
            cJSON *item = cJSON_GetObjectItem(subdata, "longitude");
            if (item == NULL || !cJSON_IsString(item)) {
                cJSON_Delete(json);
                IOTC_LOGE("get longitude error");
                return -1;
            }
            char longitude[20] = {0};
            strncpy(longitude, cJSON_GetStringValue(item), 19);
            longitude[19] = '\0';
            DEMO_LOG("longitude put %s=>%s", g_longitude, longitude);
            IOTC_LOGI("longitude put %s=>%s", g_longitude, longitude);
            if (strcmp(g_longitude, longitude)) {
                strncpy(g_longitude, longitude, 19);
                g_longitude[19] = '\0';
            }
        }
    } else {
        int size = cJSON_GetArraySize(json);
        for (int i = 0; i < size; i++) {
            cJSON *cur = cJSON_GetArrayItem(json, i);
            cJSON *st = cJSON_GetObjectItem(cur, STR_JSON_SVC_TYPE);
            if (st == NULL || !cJSON_IsString(st)) {
                cJSON_Delete(json);
                IOTC_LOGE("get st error");
                return -1;
            }
            if (strcmp(cJSON_GetStringValue(st), svc->svcType)) {
                return 0;
            }
         
            cJSON *subdata = cJSON_GetObjectItem(cur, STR_JSON_DATA);
            if (subdata == NULL) {
                cJSON_Delete(json);
                IOTC_LOGE("get data error");
                return -1;
            }
            if (cJSON_HasObjectItem(subdata, "latitude") == true) {
                cJSON *item = cJSON_GetObjectItem(subdata, "latitude");
                if (item == NULL || !cJSON_IsString(item)) {
                    cJSON_Delete(json);
                    IOTC_LOGE("get latitude error");
                    return -1;
                }
                char latitude[20] = {0};
                strncpy(latitude, cJSON_GetStringValue(item), 19);
                latitude[19] = '\0';
                DEMO_LOG("latitude put %s=>%s", g_latitude, latitude);
                IOTC_LOGI("latitude put %s=>%s", g_latitude, latitude);
                if (strcmp(g_latitude, latitude)) {
                    strncpy(g_latitude, latitude, 19);
                    g_latitude[19] = '\0';
                }
            }

            if (cJSON_HasObjectItem(subdata, "longitude") == true) {
                cJSON *item = cJSON_GetObjectItem(subdata, "longitude");
                if (item == NULL || !cJSON_IsString(item)) {
                    cJSON_Delete(json);
                    IOTC_LOGE("get longitude error");
                    return -1;
                }
                char longitude[20] = {0};
                strncpy(longitude, cJSON_GetStringValue(item), 19);
                longitude[19] = '\0';
                DEMO_LOG("longitude put %s=>%s", g_longitude, longitude);
                IOTC_LOGI("longitude put %s=>%s", g_longitude, longitude);
                if (strcmp(g_longitude, longitude)) {
                    strncpy(g_longitude, longitude, 19);
                    g_longitude[19] = '\0';
                }
            }
        }
    }

    cJSON_Delete(json);
    return 0;
}

static int32_t GpsGetCharState(const IotcServiceInfo *svc, char **data, uint32_t *len)
{
    if (data == NULL || *data != NULL) {
        IOTC_LOGE("param invalid");
        return -1;
    }

    cJSON *json = cJSON_CreateObject();
    if (json == NULL) {
        IOTC_LOGE("create obj error");
        return -1;
    }

    if (cJSON_AddStringToObject(json, "latitude", g_latitude) == NULL) {
        cJSON_Delete(json);
        IOTC_LOGE("add string error");
        return -1;
    }
    if (cJSON_AddStringToObject(json, "longitude", g_longitude) == NULL) {
        cJSON_Delete(json);
        IOTC_LOGE("add string error");
        return -1;
    }
    *data = cJSON_PrintUnformatted(json);
    cJSON_Delete(json);
    if (*data == NULL) {
        IOTC_LOGE("json print error");
        return -1;
    }
    IOTC_LOGI("latitude get %s longitude get %s", g_latitude, g_longitude);
    *len = strlen(*data);
    return 0;

}

static int32_t DevNetInfoPutCharState(const IotcServiceInfo *svc, const char *data, uint32_t len)
{
    if (data == NULL || len == 0) {
        IOTC_LOGE("param invalid");
        return -1;
    }
    cJSON *json = cJSON_Parse(data);
    if (json == NULL) {
        IOTC_LOGE("parse error");
        return -1;
    }

    if (!cJSON_IsArray(json)) {
        cJSON *st = cJSON_GetObjectItem(json, STR_JSON_SVC_TYPE);
        if (st == NULL || !cJSON_IsString(st)) {
            cJSON_Delete(json);
            IOTC_LOGE("get st error");
            return -1;
        }

        if (strcmp(cJSON_GetStringValue(st), svc->svcType)) {
            return 0;
        }
    } else {
        int size = cJSON_GetArraySize(json);
        for (int i = 0; i < size; i++) {
            cJSON *cur = cJSON_GetArrayItem(json, i);
            cJSON *st = cJSON_GetObjectItem(cur, STR_JSON_SVC_TYPE);
            if (st == NULL || !cJSON_IsString(st)) {
                cJSON_Delete(json);
                IOTC_LOGE("get st error");
                return -1;
            }

            if (strcmp(cJSON_GetStringValue(st), svc->svcType)) {
                return 0;
            }
        }
    }
    cJSON_Delete(json);
    return 0;
}

static int32_t DevNetInfoGetCharState(const IotcServiceInfo *svc, char **data, uint32_t *len)
{
    if (data == NULL || *data != NULL) {
        IOTC_LOGE("param invalid");
        return -1;
    }
    uint8_t ssid[33] = {0};
    uint8_t bssid[7] = {0};
    uint8_t bssidstr[20] = {0};
    uint8_t pwd[65] = {0};
    char ip[17] = {0};
    uint32_t ssidLen = 32;
    uint32_t bssidLen = 6;
    uint32_t pwdLen = 64;
    int8_t rssi = 0;
    int32_t ret = IotcGetWifiInfo(ssid, &ssidLen, pwd, &pwdLen);
    if (ret != IOTC_OK) {
        memset(ssid, 0, sizeof(ssid));
        memset(pwd, 0, sizeof(pwd));
    }
    IOTC_LOGI("Get ssid %s", ssid);

    ret = IotcGetLocalIp(ip, sizeof(ip));
    IOTC_LOGI("Get ip %s", ip);
    IotcGetWifiRssi(&rssi);
    IOTC_LOGI("Get rssi %d", rssi);
    IotcGetWifiBssid(bssid, bssidLen);
    IOTC_LOGI("Get bssid %02x %02x %02x %02x %02x %02x", bssid[0], bssid[1], bssid[2], bssid[3], bssid[4], bssid[5]);
    sprintf((char *)bssidstr,"%02x:%02x:%02x:%02x:%02x:%02x",bssid[0], bssid[1], bssid[2], bssid[3], bssid[4], bssid[5]);
    cJSON *json = cJSON_CreateObject();
    if (json == NULL) {
        IOTC_LOGE("create obj error");
        return -1;
    }

    if(cJSON_AddStringToObject(json, "SSID", (const char *)ssid) == NULL)
    {
        cJSON_Delete(json);
        IOTC_LOGE("add ssid error");
        return -1;
    }
    if(cJSON_AddNumberToObject(json, "RSSI", rssi) == NULL)
    {
        cJSON_Delete(json);
        IOTC_LOGE("add rssi error");
        return -1;
    }
    if(cJSON_AddStringToObject(json, "IP", ip) == NULL)
    {
        cJSON_Delete(json);
        IOTC_LOGE("add ip error");
        return -1;
    }
    if(cJSON_AddStringToObject(json, "BSSID", (const char *)bssidstr) == NULL)
    {
        cJSON_Delete(json);
        IOTC_LOGE("add bssid error");
        return -1;
    }

    *data = cJSON_PrintUnformatted(json);
    cJSON_Delete(json);
    if (*data == NULL) {
        IOTC_LOGE("json print error");
        return -1;
    }
    *len = strlen(*data);
    return 0;
}

static int32_t AllServicesPutCharState(const IotcServiceInfo *svc, const char *data, uint32_t len);
static int32_t AllServicesGetCharState(const IotcServiceInfo *svc, char **data, uint32_t *len);

/**
 * [MUST] MODIFY ME
 * SVC_MAP为服务处理函数表
 * 其中svc为SVC_INFO中的服务指针，用于标识是哪个服务
 * putCharState为控制指令处理函数
 * getCharState为查询指令处理函数
 * 开发者应实现自己的服务处理函数并添加到该表中
 */
const struct SvcMap {
    const IotcServiceInfo *svc;
    int32_t (*putCharState)(const IotcServiceInfo *svc, const char *data, uint32_t len);
    int32_t (*getCharState)(const IotcServiceInfo *svc, char **data, uint32_t *len);
} SVC_MAP[] = {
    {&SVC_INFO[0], SwitchPutCharState, SwitchGetCharState},
    {&SVC_INFO[1], SnPutCharState, SnGetCharState},
    {&SVC_INFO[2], RestartPutCharState, RestartGetCharState},
    {&SVC_INFO[3], GpsPutCharState, GpsGetCharState},
    {&SVC_INFO[4], DevNetInfoPutCharState, DevNetInfoGetCharState},
    {&SVC_INFO[5], AllServicesPutCharState, AllServicesGetCharState},
};

static int32_t AllServicesPutCharState(const IotcServiceInfo *svc, const char *data, uint32_t len)
{
    if (data == NULL || len == 0) {
        IOTC_LOGE("param invalid");
        return -1;
    }
    return 0;
}

static int32_t AllServicesGetCharState(const IotcServiceInfo *svc, char **data, uint32_t *len)
{
    
    if (data == NULL || *data != NULL) {
        IOTC_LOGE("param invalid");
        return -1;
    }
    
    int32_t num = sizeof(SVC_MAP) / sizeof(SVC_MAP[0]);

    IotcCharState state[num - 1];
    
    
    cJSON *array = cJSON_CreateArray();
    if (array == NULL) {
        IOTC_LOGE("create array error");
        return -1;
    }

    for(int32_t i = 0; i < num - 1; i++)
    {    
        SVC_MAP[i].getCharState(SVC_MAP[i].svc, (char **)&state[i].data, &state[i].len);
        
        cJSON *item = cJSON_CreateObject();
        cJSON *subdata = cJSON_CreateObject();
        if (item == NULL || subdata == NULL) {
            IOTC_LOGE("create item error");
            cJSON_Delete(array);
            return -1;
        }
        if (cJSON_AddStringToObject(item, STR_JSON_SVC_ID, SVC_MAP[i].svc->svcId) == NULL) {
            IOTC_LOGE("add sid error");
            cJSON_Delete(array);
            return -1;
        }
        if (cJSON_AddStringToObject(item, STR_JSON_SVC_TYPE, SVC_MAP[i].svc->svcType) == NULL) {
            IOTC_LOGE("add st error");
            cJSON_Delete(array);
            return -1;
        }
        if (!cJSON_AddItemToArray(array, item)) {
            IOTC_LOGE("add item error");
            cJSON_Delete(array);
            return -1;
        }
        subdata = cJSON_ParseWithLength(state[i].data, state[i].len);
        if (subdata == NULL) {
            IOTC_LOGE("build data error");
            cJSON_Delete(array);
            return -1;
        }
        if (!cJSON_AddItemToObject(item, "data", subdata)) {
            IOTC_LOGE("add data error");
            cJSON_Delete(array);
            return -1;
        }

    }
    *data = cJSON_PrintUnformatted(array);
    cJSON_Delete(array);
    if (*data == NULL) {
        IOTC_LOGE("json print error");
        return -1;
    }
    *len = strlen(*data);
    return 0;
}
/**
 * [SHOULD] MODIFY ME
 * PutCharState为注册到iot connect中的控制指令处理业务回调
 * 当收到控制指令时，该函数会通过SVC_MAP进行SID维度的控制分发
 */

static int32_t PutCharState(const IotcCharState state[], uint32_t num)
{
    if (state == NULL || num == 0) {
        IOTC_LOGE("param invalid");
        return -1;
    }

    int32_t ret = 0;
    for (uint32_t i = 0; i < num; ++i) {
        for (uint32_t j = 0; j < (sizeof(SVC_MAP) / sizeof(SVC_MAP[0])); ++j) {
            DEMO_LOG("put char sid:%s data:%s", state[i].svcId, state[i].data);
            if (strcmp(state[i].svcId, SVC_MAP[j].svc->svcId) != 0 || SVC_MAP[j].putCharState == NULL) {
                continue;
            }
            int32_t curRet = SVC_MAP[j].putCharState(SVC_MAP[j].svc, state[i].data, state[i].len);
            if (curRet != 0) {
                ret = curRet;
                DEMO_LOG("put char sid:%s error %d", state[i].svcId, ret);
            }
        }
    }
    return ret;
}

/**
 * [SHOULD] MODIFY ME
 * GetCharState为注册到iot connect中的查询指令处理业务回调
 * 当收到查询指令时，该函数会通过SVC_MAP进行SID维度的查询分发
 */
static int32_t GetCharState(const IotcCharState state[], char *out[], uint32_t len[], uint32_t num)
{
    if (state == NULL || num == 0 || out == NULL || len == NULL) {
        IOTC_LOGE("param invalid");
        return -1;
    }

    int32_t ret = 0;
    for (uint32_t i = 0; i < num; ++i) {
        for (uint32_t j = 0; j < (sizeof(SVC_MAP) / sizeof(SVC_MAP[0])); ++j) {
            DEMO_LOG("get char sid:%s", state[i].svcId);
            if (strcmp(state[i].svcId, SVC_MAP[j].svc->svcId) != 0 || SVC_MAP[j].getCharState == NULL) {
                continue;
            }
            int32_t curRet = SVC_MAP[j].getCharState(SVC_MAP[j].svc, &out[i], &len[i]);
            if (curRet != 0) {
                ret = curRet;
                DEMO_LOG("get char sid:%s error %d", state[i].svcId, ret);
            }
        }
    }

    return ret;
}
/**
 * [SHOULD] MODIFY ME
 * ReportAll为注册到iot connect中的全量服务上报业务回调
 * 当设备上线时会通过该接口上报所有可上报服务，同步端侧和APP/云侧服务状态
 */
static int32_t ReportAll(void)
{
    IotcCharState reportInfo[sizeof(SVC_MAP) / sizeof(SVC_MAP[0])] = {0};
    int32_t ret;
    for (uint32_t i = 0; i < (sizeof(SVC_MAP) / sizeof(SVC_MAP[0])); ++i) {
        reportInfo[i].svcId = SVC_MAP[i].svc->svcId;
        ret = SVC_MAP[i].getCharState(SVC_MAP[i].svc, (char **)&reportInfo[i].data, &reportInfo[i].len);
        if (ret != 0) {
            DEMO_LOG("get char sid:%s error %d", reportInfo[i].svcId, ret);
            break;
        }
    }
    if (ret == 0) {
        ret = IotcOhDevReportCharState(reportInfo, sizeof(reportInfo) / sizeof(reportInfo[0]));
    }

    for (uint32_t i = 0; i < (sizeof(SVC_MAP) / sizeof(SVC_MAP[0])); ++i) {
        if (reportInfo[i].data != NULL) {
            cJSON_free((char *)reportInfo[i].data);
            reportInfo[i].data = NULL;
        }
    }
    return ret;
}
// 为了程序编译通过
void HiLinkGetPsk(unsigned char *psk, unsigned short len)
{

}

/**
 * [SHOULD] MODIFY ME
 * GetPincode为注册到iot connect中的获取PIN码回调
 * 设备配网或执行进场控制时，会通过该接口获取PIN码用来和APP协商会话秘钥
 */
static int32_t GetPincode(uint8_t *buf, uint32_t bufLen)
{
    if (buf == NULL || bufLen > IOTC_PINCODE_LEN) {
        DEMO_LOG("param invalid");
        return -1;
    }

    #if IOTC_CONF_AILIFE_SUPPORT
    unsigned char pskBuf[16] = {0};
    extern void HiLinkGetPsk(unsigned char *psk, unsigned short len);
    HiLinkGetPsk(pskBuf, 16);

    int32_t ret = memcpy_s(buf, bufLen, pskBuf, 8);
#else
    int32_t ret = memcpy_s(buf, bufLen, PIN_CODE, strlen(PIN_CODE));
#endif
    if (ret != EOK)
    {
        return -1;
    }
    return 0;
}

/**
 * [SHOULD] MODIFY ME
 * GetAcKey为注册到iot connect中的获取AC KEY回调
 */
static int32_t GetAcKey(uint8_t *buf, uint32_t bufLen)
{
    if (buf == NULL || bufLen > IOTC_AC_KEY_LEN) {
        DEMO_LOG("param invalid");
        return -1;
    }
    int32_t ret = memcpy_s(buf, bufLen, AC_KEY, sizeof(AC_KEY));
    if (ret != EOK) {
        return -1;
    }
    return 0;
}


#if IOTC_CONF_AILIFE_SUPPORT
#define HILINK_HTTPS_CERT1                                                 \
    "-----BEGIN CERTIFICATE-----\r\n"                                      \
    "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\r\n"         \
    "-----END CERTIFICATE-----\r\n"

#define HILINK_HTTPS_CERT14                                                \
    "-----BEGIN CERTIFICATE-----\r\n"                                      \
    "MIIDXzCCAkegAwIBAgILBAAAAAABIVhTCKIwDQYJKoZIhvcNAQELBQAwTDEgMB4G\r\n" \
    "A1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjMxEzARBgNVBAoTCkdsb2JhbFNp\r\n" \
    "Z24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDkwMzE4MTAwMDAwWhcNMjkwMzE4\r\n" \
    "MTAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMzETMBEG\r\n" \
    "A1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZI\r\n" \
    "hvcNAQEBBQADggEPADCCAQoCggEBAMwldpB5BngiFvXAg7aEyiie/QV2EcWtiHL8\r\n" \
    "RgJDx7KKnQRfJMsuS+FggkbhUqsMgUdwbN1k0ev1LKMPgj0MK66X17YUhhB5uzsT\r\n" \
    "gHeMCOFJ0mpiLx9e+pZo34knlTifBtc+ycsmWQ1z3rDI6SYOgxXG71uL0gRgykmm\r\n" \
    "KPZpO/bLyCiR5Z2KYVc3rHQU3HTgOu5yLy6c+9C7v/U9AOEGM+iCK65TpjoWc4zd\r\n" \
    "QQ4gOsC0p6Hpsk+QLjJg6VfLuQSSaGjlOCZgdbKfd/+RFO+uIEn8rUAVSNECMWEZ\r\n" \
    "XriX7613t2Saer9fwRPvm2L7DWzgVGkWqQPabumDk3F2xmmFghcCAwEAAaNCMEAw\r\n" \
    "DgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFI/wS3+o\r\n" \
    "LkUkrk1Q+mOai97i3Ru8MA0GCSqGSIb3DQEBCwUAA4IBAQBLQNvAUKr+yAzv95ZU\r\n" \
    "RUm7lgAJQayzE4aGKAczymvmdLm6AC2upArT9fHxD4q/c2dKg8dEe3jgr25sbwMp\r\n" \
    "jjM5RcOO5LlXbKr8EpbsU8Yt5CRsuZRj+9xTaGdWPoO4zzUhw8lo/s7awlOqzJCK\r\n" \
    "6fBdRoyV3XpYKBovHd7NADdBj+1EbddTKJd+82cEHhXXipa0095MJ6RMG3NzdvQX\r\n" \
    "mcIfeg7jLQitChws/zyrVQ4PkX4268NXSb7hLi18YIvDQVETI53O9zJrlAGomecs\r\n" \
    "Mx86OyXShkDOOyyGeMlhLxS67ttVb9+E7gUJTb0o2HLO02JQZR7rkpeDMdmztcpH\r\n" \
    "WD9f\r\n"                                                             \
    "-----END CERTIFICATE-----\r\n"

#define HILINK_HTTPS_CERT28                                                \
    "-----BEGIN CERTIFICATE-----\r\n"                                      \
    "MIIFjTCCA3WgAwIBAgIEGErM1jANBgkqhkiG9w0BAQsFADBWMQswCQYDVQQGEwJD\r\n" \
    "TjEwMC4GA1UECgwnQ2hpbmEgRmluYW5jaWFsIENlcnRpZmljYXRpb24gQXV0aG9y\r\n" \
    "aXR5MRUwEwYDVQQDDAxDRkNBIEVWIFJPT1QwHhcNMTIwODA4MDMwNzAxWhcNMjkx\r\n" \
    "MjMxMDMwNzAxWjBWMQswCQYDVQQGEwJDTjEwMC4GA1UECgwnQ2hpbmEgRmluYW5j\r\n" \
    "aWFsIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MRUwEwYDVQQDDAxDRkNBIEVWIFJP\r\n" \
    "T1QwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDXXWvNED8fBVnVBU03\r\n" \
    "sQ7smCuOFR36k0sXgiFxEFLXUWRwFsJVaU2OFW2fvwwbwuCjZ9YMrM8irq93VCpL\r\n" \
    "TIpTUnrD7i7es3ElweldPe6hL6P3KjzJIx1qqx2hp/Hz7KDVRM8Vz3IvHWOX6Jn5\r\n" \
    "/ZOkVIBMUtRSqy5J35DNuF++P96hyk0g1CXohClTt7GIH//62pCfCqktQT+x8Rgp\r\n" \
    "7hZZLDRJGqgG16iI0gNyejLi6mhNbiyWZXvKWfry4t3uMCz7zEasxGPrb382KzRz\r\n" \
    "EpR/38wmnvFyXVBlWY9ps4deMm/DGIq1lY+wejfeWkU7xzbh72fROdOXW3NiGUgt\r\n" \
    "hxwG+3SYIElz8AXSG7Ggo7cbcNOIabla1jj0Ytwli3i/+Oh+uFzJlU9fpy25IGvP\r\n" \
    "a931DfSCt/SyZi4QKPaXWnuWFo8BGS1sbn85WAZkgwGDg8NNkt0yxoekN+kWzqot\r\n" \
    "aK8KgWU6cMGbrU1tVMoqLUuFG7OA5nBFDWteNfB/O7ic5ARwiRIlk9oKmSJgamNg\r\n" \
    "TnYGmE69g60dWIolhdLHZR4tjsbftsbhf4oEIRUpdPA+nJCdDC7xij5aqgwJHsfV\r\n" \
    "PKPtl8MeNPo4+QgO48BdK4PRVmrJtqhUUy54Mmc9gn900PvhtgVguXDbjgv5E1hv\r\n" \
    "cWAQUhC5wUEJ73IfZzF4/5YFjQIDAQABo2MwYTAfBgNVHSMEGDAWgBTj/i39KNAL\r\n" \
    "tbq2osS/BqoFjJP7LzAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAd\r\n" \
    "BgNVHQ4EFgQU4/4t/SjQC7W6tqLEvwaqBYyT+y8wDQYJKoZIhvcNAQELBQADggIB\r\n" \
    "ACXGumvrh8vegjmWPfBEp2uEcwPenStPuiB/vHiyz5ewG5zz13ku9Ui20vsXiObT\r\n" \
    "ej/tUxPQ4i9qecsAIyjmHjdXNYmEwnZPNDatZ8POQQaIxffu2Bq41gt/UP+TqhdL\r\n" \
    "jOztUmCypAbqTuv0axn96/Ua4CUqmtzHQTb3yHQFhDmVOdYLO6Qn+gjYXB74BGBS\r\n" \
    "ESgoA//vU2YApUo0FmZ8/Qmkrp5nGm9BC2sGE5uPhnEFtC+NiWYzKXZUmhH4J/qy\r\n" \
    "P5Hgzg0b8zAarb8iXRvTvyUFTeGSGn+ZnzxEk8rUQElsgIfXBDrDMlI1Dlb4pd19\r\n" \
    "xIsNER9Tyx6yF7Zod1rg1MvIB671Oi6ON7fQAUtDKXeMOZePglr4UeWJoBjnaH9d\r\n" \
    "Ci77o0cOPaYjesYBx4/IXr9tgFa+iiS6M+qf4TIRnvHST4D2G0CvOJ4RUHlzEhLN\r\n" \
    "5mydLIhyPDCBBpEi6lmt2hkuIsKNuYyH4Ga8cyNfIWRjgEj1oDwYPZTISEEdQLpe\r\n" \
    "/v5WOaHIz16eGWRGENoXkbcFgKyLmZJ956LYBws2J+dIeWCKw9cTXPhyQN9Ky8+Z\r\n" \
    "AAoACxGV2lZFA4gKn2fQ1XmxqI1AbQ3CekD6819kR5LLU7m7Wc5P/dAVUwHY3+vZ\r\n" \
    "5nbv0CO7O6l5s9UCKc2Jo5YPSjXnTkLAdc0Hz+Ys63su\r\n"                     \
    "-----END CERTIFICATE-----\r\n"
#endif


/**
 * [SHOULD] MODIFY ME
 * GetRootCA为注册到iot connect中的获取端云证书回调
 */
static int32_t GetRootCA(const char **ca[], uint32_t *num)
{
    if (ca == NULL || num == NULL) {
        DEMO_LOG("param invalid");
        return -1;
    }

    /* 填充证书 */
#if IOTC_CONF_AILIFE_SUPPORT
    static const char *CA_CERT[] = {HILINK_HTTPS_CERT1, HILINK_HTTPS_CERT14, HILINK_HTTPS_CERT28};
#else
    static const char *CA_CERT[] = {NULL};
#endif

    *ca = CA_CERT;
    *num = sizeof(CA_CERT) / sizeof(CA_CERT[0]);
    return 0;
}

/**
 * [MUST] MODIFY ME
 * NoticeReboot为注册到iot connect中的重启回调，开发者应在通知重启时重启设备或进程
 */
static int32_t NoticeReboot(IotcRebootReason res)
{
    DEMO_LOG("notice reboot res %d", res);
    return 0;
}

#define SET_OH_SDK_OPTION(ret, option, ...) \
    do { \
        (ret) = IotcOhSetOption((option), __VA_ARGS__); \
        if ((ret) != 0) { \
            IOTC_LOGE("set option %d error %d", (option), (ret)); \
            return ret; \
        } \
    } while (0);

static int32_t MakeOsBleEnable(void)
{
    int32_t ret = IOTC_OK;
    if (IsBleEnabled() == false) {
        if (EnableBle() == false) {
            IOTC_LOGE("enable ble fail");
            ret = IOTC_ERROR;
        } else {
            IOTC_LOGI("enable ble ok");
        }
    }
    /* 此处加延时为了使后面SetLocalName可以成功执行 */
    sleep(2);
    return ret;
}

static int32_t MakeOsWifiEnable(void)
{
    int32_t ret = IOTC_OK;
    if (IsWifiActive() != WIFI_STA_ACTIVE) {
        if (EnableWifi() != WIFI_SUCCESS) {
            IOTC_LOGE("enable wifi fail");
            ret = IOTC_ERROR;
        } else {
            IOTC_LOGI("enable wifi ok");
        }
    }
    return ret;
}

/**
 * [MUST] USE ME
 * IotcOhDemoEntry为iot connect业务入口，开发者应在业务进程启动时调用
 */
int32_t IotcOhDemoEntry(void)
{
    int32_t ret = IOTC_OK;
    

    /* 初始化设备信息模块 */
    ret = IotcOhDevInit();
    if (ret != 0) {
        DEMO_LOG("init device error %d", ret);
        return ret;
    }

    /* 初始化BLE发现控制模块 */
    ret = IotcOhBleEnable();
    if (ret != 0) {
        DEMO_LOG("enable ble connect error %d", ret);
        return ret;
    }

    /* 初始化Wi-Fi发现控制模块 */
    
    ret = IotcOhWifiEnable();
    if (ret != 0) {
        DEMO_LOG("enable wifi connect error %d", ret);
        return ret;
    }
    DEV_INFO.sn = GetSerial();
    IOTC_LOGI("%s get devinfo sn %s", __func__, DEV_INFO.sn);
    /* 配置iot connect必要的回调 */
    SET_OH_SDK_OPTION(ret, IOTC_OH_OPTION_DEVICE_PUT_CHAR_STATE_CALLBACK, PutCharState);
    SET_OH_SDK_OPTION(ret, IOTC_OH_OPTION_DEVICE_GET_CHAR_STATE_CALLBACK, GetCharState);
    SET_OH_SDK_OPTION(ret, IOTC_OH_OPTION_DEVICE_REPORT_ALL_CALLBACK, ReportAll);
    SET_OH_SDK_OPTION(ret, IOTC_OH_OPTION_DEVICE_GET_PINCODE_CALLBACK, GetPincode);
    SET_OH_SDK_OPTION(ret, IOTC_OH_OPTION_DEVICE_GET_AC_KEY_CALLBACK, GetAcKey);
    SET_OH_SDK_OPTION(ret, IOTC_OH_OPTION_DEVICE_DATA_FREE_CALLBACK, cJSON_free);
    SET_OH_SDK_OPTION(ret, IOTC_OH_OPTION_DEVICE_REBOOT_CALLBACK, NoticeReboot);
    SET_OH_SDK_OPTION(ret, IOTC_OH_OPTION_WIFI_GET_CERT_CALLBACK, GetRootCA);
    /* 配置设备信息与服务信息 */
    SET_OH_SDK_OPTION(ret, IOTC_OH_OPTION_DEVICE_DEV_INFO, &DEV_INFO);
    SET_OH_SDK_OPTION(ret, IOTC_OH_OPTION_DEVICE_SVC_INFO, SVC_INFO, sizeof(SVC_INFO) / sizeof(SVC_INFO[0]));
    /* 配置配网模式，根据业务场景选择 */
    SET_OH_SDK_OPTION(ret, IOTC_OH_OPTION_BLE_ENABLE_FUNC_CALLBACK, MakeOsBleEnable);
    SET_OH_SDK_OPTION(ret, IOTC_OH_OPTION_WIFI_ENABLE_FUNC_CALLBACK, MakeOsWifiEnable);
    SET_OH_SDK_OPTION(ret, IOTC_OH_OPTION_WIFI_NETCFG_MODE, IOTC_NET_CONFIG_MODE_BLE_SUP);
    /* 配置配网超时时间 */
    SET_OH_SDK_OPTION(ret, IOTC_OH_OPTION_WIFI_NETCFG_TIMEOUT, (24 * 60 * 60 * 1000));
    /* 启动后的广播超时时间 */
    SET_OH_SDK_OPTION(ret, IOTC_OH_OPTION_BLE_START_UP_ADV_TIMEOUT, (60 * 60 * 1000));
    SET_OH_SDK_OPTION(ret, IOTC_OH_OPTION_SDK_CONFIG_PATH, "/data/app/iotc/");
    
    /* 拉起iot connect业务线程 */
    ret = IotcOhMain();
    if (ret != 0) {
        DEMO_LOG("iotc oh main error %d", ret);
        return ret;
    }
    DEMO_LOG("iotc oh main success");
    return ret;
}

/**
 * [SHOULD] USE ME
 * IotcOhDemoExit为iot connect业务退出函数，开发者应在不使用相关业务并需要释放iot connect资源时调用
 */
void IotcOhDemoExit(void)
{
    int32_t ret = IotcOhStop();
    if (ret != 0) {
        DEMO_LOG("iotc stop error %d", ret);
    }
    
    ret = IotcOhWifiDisable();
    if (ret != 0) {
        DEMO_LOG("iotc wifi disable error %d", ret);
    }
    
    ret = IotcOhBleDisable();
    if (ret != 0) {
        DEMO_LOG("iotc ble disable error %d", ret);
    }

    ret = IotcOhDevDeinit();
    if (ret != 0) {
        DEMO_LOG("iotc dev info deinit error %d", ret);
    }
}

/**
 * [MUST] USE ME
 * IotcOhDemoRestore为iot connect恢复出厂函数，开发者应在设备被重置时调用
 */
void IotcOhDemoRestore(void)
{
    DEMO_LOG("restore");
    IotcOhRestore();
}

/**
 * [MUST] USE ME
 * IotcOhDemoReport为设备数据变化上报的DEMO函数，开发者应在设备服务发生主动变化时调用该接口上报
 */
void IotcOhDemoReport(const char *sid)
{
    DEMO_LOG("report");
    if (sid == NULL) {
        DEMO_LOG("report sid null");
        return;
    }
    IotcCharState reportInfo = {0};
    int32_t ret = -1;
    for (uint32_t i = 0; i < (sizeof(SVC_MAP) / sizeof(SVC_MAP[0])); ++i) {
        if (SVC_MAP[i].svc->svcId == NULL || SVC_MAP[i].getCharState == NULL ||
            strcmp(sid, SVC_MAP[i].svc->svcId) != 0) {
            continue;
        }
        reportInfo.svcId = SVC_MAP[i].svc->svcId;
        ret = SVC_MAP[i].getCharState(SVC_MAP[i].svc, (char **)&reportInfo.data, &reportInfo.len);
        if (ret != 0) {
            DEMO_LOG("get char sid:%s error %d", sid, ret);
        }
        break;
    }
    if (ret == 0) {
        ret = IotcOhDevReportCharState(&reportInfo, 1);
        if (ret != 0) {
            DEMO_LOG("report char sid:%s error %d", sid, ret);
        } else {
            DEMO_LOG("report char sid:%s success", sid);
        }
    }

    if (reportInfo.data != NULL) {
        cJSON_free((char *)reportInfo.data);
    }
    return;
}

int main(void)
{
    DEMO_LOG("sleep 30 seconds to wait wifi ready.");
    sleep(30);
    system("power-shell wakeup");
    system("power-shell setmode 602");
    IotcOhDemoEntry();
    while (true)
    {
        sleep(1);
        if (getScreenState() == 0 && IsNetworkConnected() == false) {
            IOTC_LOGI("wakeup to connect wifi");
            system("power-shell wakeup");
        }
    }
    return 0;
}
